package com.satan.novel.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.satan.novel.common.constant.CacheConsts;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;

import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
// 标注该类为Spring Boot的配置类，用于定义缓存相关的Bean
public class CacheConfig {

    /**
     * 创建Caffeine本地缓存管理器
     */
    @Bean
    // 标记此方法返回的对象作为Spring容器中的一个Bean，并且在多个CacheManager存在时设置为首选
    @Primary
    public CacheManager caffeineCacheManager() {
        // 初始化一个SimpleCacheManager实例，用于管理多种类型的缓存
        SimpleCacheManager cacheManager = new SimpleCacheManager();

        // 创建一个存放CaffeineCache对象的列表，大小与预定义的Cache枚举数量一致
        List<CaffeineCache> caches = new ArrayList<>(CacheConsts.CacheEnum.values().length);

        // 遍历预定义的Cache枚举，为符合条件（isLocal为true）的缓存创建Caffeine缓存实例
        for (var c : CacheConsts.CacheEnum.values()) {
            if (c.isLocal()) {
                // 使用Caffeine.newBuilder()构建缓存配置对象
                Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
                        // 记录缓存统计信息
                        .recordStats()
                        // 设置缓存的最大容量
                        .maximumSize(c.getMaxSize());

                // 如果缓存有设置过期时间，则设置写入后存活时间
                if (c.getTtl() > 0) {
                    caffeine.expireAfterWrite(Duration.ofSeconds(c.getTtl()));
                }

                // 创建CaffeineCache实例并添加到缓存列表中
                caches.add(new CaffeineCache(c.getName(), caffeine.build()));
            }
        }

        // 将所有创建的Caffeine缓存实例设置到SimpleCacheManager中
        cacheManager.setCaches(caches);

        // 返回配置好的Caffeine本地缓存管理器
        return cacheManager;
    }

    /**
     * 创建Redis远程缓存管理器
     */
    @Bean
    // 标记此方法返回的对象作为Spring容器中的一个Bean
    public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
        // 创建非锁定模式的Redis缓存写入器
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);

        // 创建默认的Redis缓存配置，禁用缓存null值，并为缓存名添加前缀
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .disableCachingNullValues().prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX);

        // 创建一个Map，键为缓存名，值为对应的Redis缓存配置
        Map<String, RedisCacheConfiguration> cacheMap = new LinkedHashMap<>(CacheConsts.CacheEnum.values().length);

        // 遍历预定义的Cache枚举，为符合条件（isRemote为true）的缓存创建Redis缓存配置
        for (var c : CacheConsts.CacheEnum.values()) {
            if (c.isRemote()) {
                // 根据是否设置了过期时间，创建具有相应TTL的Redis缓存配置项
                if (c.getTtl() > 0) {
                    cacheMap.put(c.getName(),
                            RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
                                    .prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX)
                                    .entryTtl(Duration.ofSeconds(c.getTtl())));
                } else {
                    cacheMap.put(c.getName(),
                            RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
                                    .prefixCacheNameWith(CacheConsts.REDIS_CACHE_PREFIX));
                }
            }
        }

        // 初始化Redis缓存管理器，使用已创建的缓存写入器、默认配置和自定义配置Map
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, cacheMap);

        // 设置Redis缓存管理器支持事务
        redisCacheManager.setTransactionAware(true);

        // 初始化所有缓存
        redisCacheManager.initializeCaches();

        // 返回配置好的Redis远程缓存管理器
        return redisCacheManager;
    }
}
